#include "semantic_analyzer.h"
#include "syntax_tree.h"
#include "main_container.h"
#include "errors_warnings.h" 
extern MainContainer * CompilerData;
#include "semantics_class.h"
#include "semantics_method.h"
#include "lexic_unit.h"
#include "main_container.h"

/*
SemanticsMethodStatement * ReadMethodStatement(SyntaxTreeNode * methodStatementNode); (Gr_MethodStatements__MethodStatement_MethodStatements, Gr_MethodStatements__***)
SemanticsMethodBody * ReadMethodBody(SyntaxTreeNode * methodBodyNode); (Gr_MethodBodyDecl__spLCBrac_MethodBody_spRCBrac, Gr_MethodBodyDecl__spSemiCol, Gr_MethodBody__LabelMethodStatement_MethodBody)
SemanticsMethodStatementIf * ReadMSIf(SyntaxTreeNode * msIfNode); (Gr_MethodStatement__IfStatement, Gr_IfStatement__if_spLPar_Expression_spRPar_StatementEnding_ElsePart)
SemanticsMethodStatementWhile * ReadMSWhile(SyntaxTreeNode * msWhileNode); (Gr_MethodStatement__WhileStatement, Gr_WhileStatement__while_spLPar_Expression_spRPar_StatementEnding)
SemanticsMethodStatementFor * ReadMSFor(SyntaxTreeNode * msForNode); (Gr_ForStatement__for_spLPar_SimpleStatement_spSemiCol_Expression_spSemiCol_SimpleStatement_spRPar_StatementEnding, Gr_MethodStatement__ForStatement)
SemanticsMethodStatementDoWhile * ReadMSDoWhile(SyntaxTreeNode * msDoWhileNode); (Gr_MethodStatement__DowhileStatement, Gr_DowhileStatement__do_StatementEnding_while_spLPar_Expression_spRPar_spSemiCol)
*/



//Gr_MethodStatement__VariableDefinition
//Gr_MethodStatement__Assignment
//Gr_MethodStatement__MethodCall
//Gr_MethodStatement__IfStatement
//Gr_MethodStatement__WhileStatement
//Gr_MethodStatement__ForStatement
//Gr_MethodStatement__DowhileStatement
//Gr_MethodStatement__SwitchCaseStatement
//Gr_MethodStatement__BreakStatement
//Gr_MethodStatement__ContinueStatement
//Gr_MethodStatement__ReturnStatement
//Gr_MethodStatement__GotoStatement
//Gr_MethodStatement__StartStatement
//Gr_MethodStatement__StopStatement
//Gr_MethodStatement__AssignmentDerivation
//Gr_MethodStatement__BlockStatement

SemanticsMethodStatement * SemanticAnalyzer::ReadMethodStatement(SyntaxTreeNode * methodStatementNode)
{
#ifdef TRACE 
    CompilerData->LogTrace->ReportEntry("ReadMethodStatement");
#endif	 
	SemanticsMethodStatement * sms;
	sms = new SemanticsMethodStatement(); 
    // check production validity   

	if (methodStatementNode->Production == Gr_MethodStatement__VariableDefinition)
	{
		// <method_statement> ~ <variable_definition>  {trace, int, float, bool, state, time, void, Facility, Storage, Queue, ADTable, Group, OutputStream, NAME}
		
		//TODO

	}
	else if (methodStatementNode->Production == Gr_MethodStatement__Assignment)
    {
		// <method_statement> ~ <assignment>
	
		SyntaxTreeNode * assignmentNode = methodStatementNode->Nodes->GetData(0);

		SemanticsMethodStatementAssignment * smsa = ReadMSAssignment(assignmentNode);
	
		// smsa->Label = -1; // TODO
		// smsa->Type = MetStatAssignment;


#ifdef TRACE
		CompilerData->LogTrace->ReportExit("ReadMethodStatement");	
#endif
		return (SemanticsMethodStatement *) smsa; 

	}
	else if (methodStatementNode->Production == Gr_MethodStatement__MethodCall)
	{
		// <method_statement> ~ <method_call>
		SyntaxTreeNode * methodCallNode = methodStatementNode->Nodes->GetData(0);
		SemanticsMethodStatementMethodCall * smsmc = ReadMSMethodCall(methodCallNode);

		smsmc->Label = -1; // TODO
		smsmc->Type = MetStatAssignment;


#ifdef TRACE
		CompilerData->LogTrace->ReportExit("ReadMethodStatement");	
#endif		  
		return (SemanticsMethodStatement *) smsmc;
	}
	else if (methodStatementNode->Production == Gr_MethodStatement__IfStatement)
    {
		// <method_statement> ~ <if_statement>
	
		SyntaxTreeNode * ifStatementNode = methodStatementNode->Nodes->GetData(0);
		SemanticsMethodStatementIf *smsi = ReadMSIf(ifStatementNode);

#ifdef TRACE
		CompilerData->LogTrace->ReportExit("ReadMethodStatement");	
#endif
		return (SemanticsMethodStatement *) smsi;
	}
	else if (methodStatementNode->Production == Gr_MethodStatement__WhileStatement)
    {
		// <method_statement> ~ <while_statement>  {while}

		SyntaxTreeNode * whileStatementNode = methodStatementNode->Nodes->GetData(0);
		SemanticsMethodStatementWhile *smsw = ReadMSWhile(whileStatementNode);


#ifdef TRACE
		CompilerData->LogTrace->ReportExit("ReadMethodStatement");	
#endif
		return (SemanticsMethodStatement *) smsw;
	}
	else if (methodStatementNode->Production == Gr_MethodStatement__ForStatement)
	{
		// <method_statement> ~ <for_statement>  {for}

		SyntaxTreeNode * forStatementNode = methodStatementNode->Nodes->GetData(0);
		SemanticsMethodStatementFor * smsf  = ReadMSFor(forStatementNode);

		
#ifdef TRACE
		CompilerData->LogTrace->ReportExit("ReadMethodStatement");	
#endif
        return (SemanticsMethodStatement *) smsf;
	}
	else if (methodStatementNode->Production == Gr_MethodStatement__DowhileStatement)
	{
		// <method_statement> ~ <dowhile_statement>  {do}
	
		SyntaxTreeNode * dowhileStatementNode = methodStatementNode->Nodes->GetData(0);
		SemanticsMethodStatementDoWhile * smsdw  = ReadMSDoWhile(dowhileStatementNode);
		
#ifdef TRACE
		CompilerData->LogTrace->ReportExit("ReadMethodStatement");	
#endif
		return (SemanticsMethodStatement *) smsdw;
	}
	else if (methodStatementNode->Production == Gr_MethodStatement__SwitchCaseStatement )
	{
		// <method_statement> ~ <switch_case_statement>  {switch}
	
		SyntaxTreeNode * switchCaseNode = methodStatementNode->Nodes->GetData(0);
		SemanticsMethodStatementSwitchCase * smssc  = ReadMSSwitchCase(switchCaseNode);

#ifdef TRACE
		CompilerData->LogTrace->ReportExit("ReadMethodStatement");	
#endif
		return (SemanticsMethodStatement *) smssc;
	}
	else if (methodStatementNode->Production == Gr_MethodStatement__BreakStatement)
	{
		// <method_statement> ~ <break_statement>  {break}

		SyntaxTreeNode * breakNode = methodStatementNode->Nodes->GetData(0);
		SemanticsMethodStatementBreak * smsb  = ReadMSBreak(breakNode);
	
#ifdef TRACE
		CompilerData->LogTrace->ReportExit("ReadMethodStatement");	
#endif
		return (SemanticsMethodStatement *) smsb;
	}
	else if (methodStatementNode->Production == Gr_MethodStatement__ContinueStatement)
	{
		// <method_statement> ~ <continue_statement>  {continue}
		
		SyntaxTreeNode * continueNode = methodStatementNode->Nodes->GetData(0);
		SemanticsMethodStatementContinue * smsc  = ReadMSContinue(continueNode);


#ifdef TRACE
		CompilerData->LogTrace->ReportExit("ReadMethodStatement");	
#endif		
		return (SemanticsMethodStatement *) smsc;
	}
	else if (methodStatementNode->Production == Gr_MethodStatement__ReturnStatement)
	{
		// <method_statement> ~ <return_statement>  {return}
		SyntaxTreeNode * returnNode = methodStatementNode->Nodes->GetData(0);
		SemanticsMethodStatementReturn * smsr  = ReadMSReturn(returnNode);
		
#ifdef TRACE
		CompilerData->LogTrace->ReportExit("ReadMethodStatement");	
#endif		
		return (SemanticsMethodStatement *) smsr;
	}
	else if (methodStatementNode->Production == Gr_MethodStatement__GotoStatement)
	{
		// <method_statement> ~ <goto_statement>  {goto}
		SyntaxTreeNode * gotoNode = methodStatementNode->Nodes->GetData(0);
		SemanticsMethodStatementGoto * smsg  = ReadMSGoto(gotoNode);


#ifdef TRACE
		CompilerData->LogTrace->ReportExit("ReadMethodStatement");	
#endif
		return (SemanticsMethodStatement *) smsg;	
	}
	else if (methodStatementNode->Production == Gr_MethodStatement__StartStatement)
	{
		// <method_statement> ~ <start_statement>  {start}

		SyntaxTreeNode * startNode = methodStatementNode->Nodes->GetData(0);
		SemanticsMethodStatementStart * smss  = ReadMSStart(startNode);


#ifdef TRACE
		CompilerData->LogTrace->ReportExit("ReadMethodStatement");	
#endif
		return (SemanticsMethodStatement *) smss;	
	}
	else if (methodStatementNode->Production == Gr_MethodStatement__StopStatement)
	{
		// <method_statement> ~ <stop_statement>  {stop}
	
		SyntaxTreeNode * stopNode = methodStatementNode->Nodes->GetData(0);
		SemanticsMethodStatementStop * smssp  = ReadMSStop(stopNode);

#ifdef TRACE
		CompilerData->LogTrace->ReportExit("ReadMethodStatement");	
#endif
		return (SemanticsMethodStatement *) smssp;
	}
	else if (methodStatementNode->Production == Gr_MethodStatement__AssignmentDerivation)
	{
		// <method_statement> ~ <assignment_derivation>  {derivation}

		SyntaxTreeNode * assignmentDerNode = methodStatementNode->Nodes->GetData(0);
		SemanticsMethodStatementDerivationAssignment * smsda  = ReadMSDerivationAssignment(assignmentDerNode);
		
        
#ifdef TRACE
		CompilerData->LogTrace->ReportExit("ReadMethodStatement");	
#endif
		return (SemanticsMethodStatement *) smsda;		
	}
	else if (methodStatementNode->Production == Gr_MethodStatement__BlockStatement)
	{
		// <method_statement> ~ <block_statement>  {{}	
	
		SyntaxTreeNode * blockStatementNode = methodStatementNode->Nodes->GetData(01);
		if(blockStatementNode->Production == Gr_BlockStatement__spLCBrac_MethodBody_spRCBrac)
		{
			SyntaxTreeNode * methodBodyNode = blockStatementNode->Nodes->GetData(1);
            
			SemanticsMethodBody * smb = ReadMethodBody(methodBodyNode);


#ifdef TRACE
			CompilerData->LogTrace->ReportExit("ReadMethodStatement");	
#endif
			return (SemanticsMethodStatement *) smb;
		}			
	}	


#ifdef TRACE
	CompilerData->LogTrace->ReportExit("ReadMethodStatement");
#endif
	return sms;
}



//Gr_MethodBodyDecl__spLCBrac_MethodBody_spRCBrac
//Gr_MethodBodyDecl__spSemiCol
//Gr_MethodBody__LabelMethodStatement_MethodBody
//Gr_MethodBody__epsilon

SemanticsMethodBody * SemanticAnalyzer::ReadMethodBody(SyntaxTreeNode * methodBodyNode)
{
#ifdef TRACE
    CompilerData->LogTrace->ReportEntry("ReadMethodBody");
#endif

	SemanticsMethodBody * smb;

	 // check production validity
    if (methodBodyNode->Production == Gr_MethodBodyDecl__spLCBrac_MethodBody_spRCBrac)
    {
		// <method_body_decl> ~ { <method_body> }  {{}
		SyntaxTreeNode * metodBody = methodBodyNode->Nodes->GetData(1);
		smb = ReadMethodBody(metodBody);
    }
	else if (methodBodyNode->Production == Gr_MethodBodyDecl__spSemiCol)
	{
		// <method_body> ~ <label_method_statement> <method_body>  {NAME, if, while, for, do, switch, break, continue, return, goto, start, stop, derivation, trace, int, float, bool, state, time, void, Facility, Storage, Queue, ADTable, Group, OutputStream}
		smb = new SemanticsMethodBody();
		smb->Body = NULL;
	}	
	else if (methodBodyNode->Production == Gr_MethodBody__LabelMethodStatement_MethodBody)
	{
		// <method_body> ~ <label_method_statement> <method_body>  {NAME, if, while, for, do, switch, break, continue, return, goto, start, stop, derivation, trace, int, float, bool, state, time, void, Facility, Storage, Queue, ADTable, Group, OutputStream}
		smb = new SemanticsMethodBody();
		
		SyntaxTreeNode * statementLabelMetod = methodBodyNode->Nodes->GetData(0);

		//smb-> = ....??????????????????? --> 
		// TODO -> change ????
		for(int i = 0; i < methodBodyNode->Nodes->GetCount(); i++)
		{
			SemanticsMethodStatement * sms = ReadMethodStatement(methodBodyNode->Nodes->GetData(i));
			smb->Body->Add(sms);
		}

//		SyntaxTreeNode * bodyMethod = methodBodyNode->Nodes->GetData(1);
//		smb = ReadMethodBody(bodyMethod);
	}
	else
    {
        // ERROR has been found
        // MAKE LOGICAL RECOVERING
    }

#ifdef TRACE
    CompilerData->LogTrace->ReportExit("ReadMethodBody");
#endif

	return smb;
};



//Gr_MethodStatement__IfStatement
//Gr_IfStatement__if_spLPar_Expression_spRPar_BlockStatement_ElsePart

SemanticsMethodStatementIf * SemanticAnalyzer::ReadMSIf(SyntaxTreeNode * msIfNode)
{
#ifdef TRACE
    CompilerData->LogTrace->ReportEntry("ReadMSIf");
#endif

	SemanticsMethodStatementIf * smsi;
	smsi = new SemanticsMethodStatementIf();

	if(msIfNode->Production == Gr_MethodStatement__IfStatement)
	{
		// <method_statement> ~ <if_statement>  {if}

		SyntaxTreeNode * ifStatementNode = msIfNode->Nodes->GetData(0);
		smsi = ReadMSIf(ifStatementNode);
	}

	else if(msIfNode->Production == Gr_IfStatement__if_spLPar_Expression_spRPar_BlockStatement_ElsePart)
	{
		SyntaxTreeNode * expressionNode = msIfNode->Nodes->GetData(2);
		smsi->Expression = GatherFromExpression(expressionNode);

		SyntaxTreeNode * blockStatementNode = msIfNode->Nodes->GetData(4);
				
		if(blockStatementNode->Production == Gr_BlockStatement__spLCBrac_MethodBody_spRCBrac)
		{
			SyntaxTreeNode * methodBodyNode = blockStatementNode->Nodes->GetData(1);
			smsi->BodyIf = ReadMethodBody(methodBodyNode);
			
         }		

		SyntaxTreeNode * elsePartNode = msIfNode->Nodes->GetData(5);	

		if(elsePartNode->Production == Gr_ElsePart__else_BlockStatement)
		{
			// <else_part> ~ else <block_statement>  {else}
			SyntaxTreeNode * blockStatementNode = elsePartNode->Nodes->GetData(1);
			
			if(blockStatementNode->Production == Gr_BlockStatement__spLCBrac_MethodBody_spRCBrac)
			{
				SyntaxTreeNode * methodBodyNode = blockStatementNode->Nodes->GetData(1);
				smsi->BodyElse = ReadMethodBody(methodBodyNode);			
			}
		}
	}
		else
	{
		// ERROR has been found
		// MAKE LOGICAL RECOVERING
	}

	return smsi;

#ifdef TRACE
	CompilerData->LogTrace->ReportExit("ReadMSIf");
#endif
}


//Gr_MethodStatement__WhileStatement
// <method_statement> ~ <while_statement>  {while}

	// <while_statement> ~ while ( <expression> ) <block_statement>  {while}
	//Gr_WhileStatement__while_spLPar_Expression_spRPar_BlockStatement,

SemanticsMethodStatementWhile * SemanticAnalyzer::ReadMSWhile(SyntaxTreeNode * msWhileNode)
{
#ifdef TRACE
    CompilerData->LogTrace->ReportEntry("ReadMSWhile");
#endif

	SemanticsMethodStatementWhile * smsw;
	smsw = new SemanticsMethodStatementWhile();

	if(msWhileNode->Production == Gr_MethodStatement__WhileStatement)
	{
		// <method_statement> ~ <while_statement>  {while}

		SyntaxTreeNode * whileStatementNode = msWhileNode->Nodes->GetData(0);
		smsw = ReadMSWhile(whileStatementNode);
	}
		
	else if(msWhileNode->Production == Gr_WhileStatement__while_spLPar_Expression_spRPar_BlockStatement)
	{
		SyntaxTreeNode * expressionNode = msWhileNode->Nodes->GetData(1);
		smsw->Expression = GatherFromExpression(expressionNode);

		SyntaxTreeNode * blockStatementNode = msWhileNode->Nodes->GetData(4);
		if(blockStatementNode->Production == Gr_BlockStatement__spLCBrac_MethodBody_spRCBrac)
		{
			SyntaxTreeNode * methodBodyNode = blockStatementNode->Nodes->GetData(1);
			smsw->LoopBody = ReadMethodBody(methodBodyNode);
		}
	}
	else
	{
		// ERROR has been found
		// MAKE LOGICAL RECOVERING
	}

	return smsw;

#ifdef TRACE
	CompilerData->LogTrace->ReportExit("ReadMSWhile");
#endif
}



//Gr_ForStatement__for_spLPar_SimpleStatement_spSemiCol_Expression_spSemiCol_SimpleStatement_spRPar_BlockStatement
//Gr_MethodStatement__ForStatement
	
 SemanticsMethodStatementFor * SemanticAnalyzer::ReadMSFor(SyntaxTreeNode * msForNode)
{
#ifdef TRACE
    CompilerData->LogTrace->ReportEntry("ReadMSFor");
#endif

	SemanticsMethodStatementFor * smsf;
	smsf = new SemanticsMethodStatementFor();
	
	if(msForNode->Production == Gr_ForStatement__for_spLPar_SimpleStatement_spSemiCol_Expression_spSemiCol_SimpleStatement_spRPar_BlockStatement)
	{		
		SyntaxTreeNode * simpleStatementNode = msForNode->Nodes->GetData(2);
		smsf->InitializationStatement = ReadMethodStatement(simpleStatementNode);

		SyntaxTreeNode * expressionNode = msForNode->Nodes->GetData(4);
		smsf->Expression = GatherFromExpression(expressionNode);

		simpleStatementNode = msForNode->Nodes->GetData(6);
		smsf->RepeatStatement = ReadMethodStatement(simpleStatementNode);
					
		SyntaxTreeNode * blockStatementNode = msForNode->Nodes->GetData(8);
		if(blockStatementNode->Production == Gr_BlockStatement__spLCBrac_MethodBody_spRCBrac)
		{
			SyntaxTreeNode * methodBodyNode = blockStatementNode->Nodes->GetData(1);
			smsf->LoopBody = ReadMethodBody(methodBodyNode);
		}
	}
	
	else if(msForNode->Production == Gr_MethodStatement__ForStatement)
	{
		// <method_statement> ~ <for_statement>  {for}

		SyntaxTreeNode * forStatementNode = msForNode->Nodes->GetData(0);
		smsf = ReadMSFor(forStatementNode);
	}

	else
	{
		// ERROR has been found
		// MAKE LOGICAL RECOVERING
	}

	return smsf;

#ifdef TRACE
	CompilerData->LogTrace->ReportExit("ReadMSFor");
#endif
}



//Gr_MethodStatement__DowhileStatement
//Gr_DowhileStatement__do_BlockStatement_while_spLPar_Expression_spRPar_spSemiCol

SemanticsMethodStatementDoWhile * SemanticAnalyzer::ReadMSDoWhile(SyntaxTreeNode * msDoWhileNode)
{
#ifdef TRACE
    CompilerData->LogTrace->ReportEntry("ReadMSDoWhile");
#endif

	SemanticsMethodStatementDoWhile * smsdw;
	smsdw = new SemanticsMethodStatementDoWhile();
	if(msDoWhileNode->Production == Gr_MethodStatement__DowhileStatement)
	{
		// <method_statement> ~ <dowhile_statement>  {do}
        //SyntaxTreeNode * dowhileStatementNode = msDoWhileNode->Nodes->GetData(0);
       smsdw = ReadMSDoWhile(msDoWhileNode->Nodes->GetData(0));
	}

	else if(msDoWhileNode->Production == Gr_DowhileStatement__do_BlockStatement_while_spLPar_Expression_spRPar_spSemiCol)
	{

		SyntaxTreeNode * blockStatementNode = msDoWhileNode->Nodes->GetData(1);
		if(blockStatementNode->Production == Gr_BlockStatement__spLCBrac_MethodBody_spRCBrac)
		{
			SyntaxTreeNode * methodBodyNode = blockStatementNode->Nodes->GetData(1);
			smsdw->LoopBody = ReadMethodBody(methodBodyNode);

		}		
						
		SyntaxTreeNode * expressionNode = msDoWhileNode->Nodes->GetData(4);
		smsdw->Expression = GatherFromExpression(expressionNode);
	}
		 
	else
	{
		// ERROR has been found
		// MAKE LOGICAL RECOVERING
	}

	return smsdw;

#ifdef TRACE
	CompilerData->LogTrace->ReportExit("ReadMSDoWhile");
#endif
}